/*
 * Serial.cpp
 *
 *  Created on: Mar 18, 2011
 *      Author: user
 */
#include "bilbao/util/SerialPort.h"

namespace bilbao
{
	namespace util
	{
		//--------------------------------------------------------------------------------
		SerialPort::SerialPort(void)
			: _fd(0)
		{
		#if BILBAO_PLATAFORM == BILBAO_WIN32
			_port = std::string( "COM10" );
		#else
			_port = std::string( "/dev/ttyGS0" );
		#endif

			configure(B9600, 0, 1, CS8);
		}
		//--------------------------------------------------------------------------------
		SerialPort::SerialPort( const char* port )
			: _fd(0), _port( port )
		{
			configure(B9600, 0, 1, CS8);
		}
		//--------------------------------------------------------------------------------
		SerialPort::SerialPort( const char* port, int baudrate, int parity, int stopbit, int bits_dados )
			: _fd(0), _port( port )
		{
			configure( baudrate, parity, stopbit, bits_dados );
		}
		//--------------------------------------------------------------------------------
		SerialPort::~SerialPort(void)
		{
			finalize();
		}
		//--------------------------------------------------------------------------------
		void SerialPort::configure( int baudrate, int parity, int stopbit, int bits_dados )
		{
			//struct termios comm_config_orig; /* configuracao original */ //TODO: Retirar essa variável
			struct termios newtio;

			/**
			 * 1º passo: Abrir a porta sérial
			 * A porta é aberta para leitura e escrita (O_RDWR) e o programa não fica o processo controlador do terminal (O_NOCTTY)
			 */
			_fd = open( _port.c_str(), O_RDWR | O_NOCTTY);
			if ( _fd < 0 )
			{
				//LOGGER("SerialPort.log", lang::Logger::L_ERROR, "Não foi possível abrir conexão com a porta serial especificada.");
				return;
			}

			/* Depois da porta aberta, guardar valores da configuração */
			/* anterior e criar a nova configuracao */
			//tcgetattr(_fd, &comm_config_orig); /* guarda valores antigos */
			bzero(&newtio, sizeof(newtio)); /* limpa nova configuracao */

			/*
			 Configuracao das c_flags

			 B19200 : Baudrate
			 CS8 : 8 data bits
			 CLOCAL : ligacao local, ignorar linhas de controle do modem
			 CREAD : autorizar recepcao de caracteres
			 sem CRTSCTS : sem controlo por hardware
			 */
			newtio.c_cflag = baudrate;
			newtio.c_cflag |= (bits_dados | CLOCAL | CREAD);

			/*
			 Configuracao das c_iflags:
			 IGNPAR : ignorar erros de paridade;
			 ICRNL : transforma "carriage return" em "newline" à entrada.
			 */
			newtio.c_iflag = IGNBRK | IGNPAR | ICRNL;

			/* Configuracao das c_oflags */
			newtio.c_oflag = ONLCR;

			/* Configuracao das c_lflags */
			newtio.c_lflag = 0;

			/* Configuracao do timeout entre caracteres recebidos */
			newtio.c_cc[VTIME] = 0; /* timeout em 1/10s */
			newtio.c_cc[VMIN] = 0; /* não tem numero limite de caracteres */

			/* Limpar a linha série antes de activar a nova configuracao */
			tcflush(_fd, TCIFLUSH);
			tcsetattr(_fd, TCSANOW, &newtio);

			std::cout << "Configurou!!![2]" << std::endl;
		}
		//--------------------------------------------------------------------------------
		int SerialPort::send( const char c )
		{
			if ( _fd )
			{
				return write( _fd, &c, 1 );
			}

			return -1;
		}
		//--------------------------------------------------------------------------------
		int SerialPort::send( const char* str, int sz )
		{
			//Verifica se existe um file descriptor associado e se a string não é nula.
			if ( _fd && str )
			{
				return write( _fd, str, sz ); //Escreve o vetor na porta serial
			}

			return -1;
		}
		//--------------------------------------------------------------------------------
		int SerialPort::receive( char* c )
		{
			if ( _fd )
			{
				return read( _fd, c, 1 );
			}

			return -1;
		}
		//--------------------------------------------------------------------------------
		int SerialPort::receive( char** str , int sz )
		{
			int i = 0;
			char c;

			if ( _fd && str )
			{
				while ( (i < sz) && (receive(&c) > 0) )
				{
					*str[i++];
				}

				return sz;
			}

			return -1;
		}
		//--------------------------------------------------------------------------------
		void SerialPort::finalize(void)
		{
			if ( _fd )
			{
				close( _fd );
			}
		}
		//--------------------------------------------------------------------------------
	}
}
